﻿//===================================================================================
// Copyright (c) Ryan Garrett.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===================================================================================

using Caffeine.Core.Test.TestModel;
using Caffeine.Core.Test.TestModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace Caffeine.Core.Test
{
    [TestClass]
    public class ModelCollectionTester
    {
        [TestMethod]
        public void ModelCollectionPropertyChangeTest()
        {
            IModelFactory factory = new ModelFactory();
            ModelForCollectionPropertyChangeTest viewModel = factory.CreateModel<ModelForCollectionPropertyChangeTest>();
            ModelForCollectionPropertyChangeTest childA = factory.CreateModel<ModelForCollectionPropertyChangeTest>();
            ModelForCollectionPropertyChangeTest childB = factory.CreateModel<ModelForCollectionPropertyChangeTest>();

            Int32 callCount = 0;

            factory.PropertyChangeCounter.AddObserver
            (
                (propertyCount, property) =>
                {
                    callCount++;
                    Assert.AreEqual(viewModel.Children, property);
                }
            );

            viewModel.Children.Add(childA);
            viewModel.Children.Add(childB);
            viewModel.Children.Swap(childA, childB);
        }

        [TestMethod]
        public void ValidationMethodChainTest()
        {
            ModelForCollectionPropertyChangeTest viewModel = Creator.Create<ModelForCollectionPropertyChangeTest>();
            Int32 validationMethod1Called = 0;
            Int32 validationMethod2Called = 0;
            Int32 validationMethod3Called = 0;
            List<string> validationCalls = new List<string>();

            viewModel.Children.ChainValidationMethod(null);
            Assert.IsNull(viewModel.Children.ValidationMethod);

            viewModel.Children.ChainValidationMethod(null);
            Assert.IsNull(viewModel.Children.ValidationMethod);

            viewModel.Children.ChainValidationMethod
            (
                (
                    ModelCollection<ModelForCollectionPropertyChangeTest> collection,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = true; validationMethod1Called++; validationCalls.Add("Method1"); }
            );
            Assert.IsNotNull(viewModel.Children.ValidationMethod);
            viewModel.Children.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationCalls.Count, 1);
            Assert.AreEqual(validationCalls[0], "Method1");

            validationMethod1Called = 0;
            validationCalls.Clear();

            viewModel.Children.ChainValidationMethod(null);
            Assert.IsNotNull(viewModel.Children.ValidationMethod);
            viewModel.Children.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationCalls.Count, 1);
            Assert.AreEqual(validationCalls[0], "Method1");

            validationMethod1Called = 0;
            validationCalls.Clear();

            viewModel.Children.ChainValidationMethod
            (
                (
                    ModelCollection<ModelForCollectionPropertyChangeTest> collection,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = true; validationMethod2Called++; validationCalls.Add("Method2"); }
            );
            Assert.IsNotNull(viewModel.Children.ValidationMethod);
            viewModel.Children.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationMethod2Called, 1);
            Assert.AreEqual(validationCalls.Count, 2);
            Assert.AreEqual(validationCalls[0], "Method1");
            Assert.AreEqual(validationCalls[1], "Method2");

            validationMethod1Called = 0;
            validationMethod2Called = 0;
            validationCalls.Clear();

            viewModel.Children.ChainValidationMethod
            (
                (
                    ModelCollection<ModelForCollectionPropertyChangeTest> collection,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { validationMethod3Called++; validationCalls.Add("Method3"); }
            );
            Assert.IsNotNull(viewModel.Children.ValidationMethod);
            viewModel.Children.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationMethod2Called, 1);
            Assert.AreEqual(validationMethod3Called, 1);
            Assert.AreEqual(validationCalls.Count, 3);
            Assert.AreEqual(validationCalls[0], "Method1");
            Assert.AreEqual(validationCalls[1], "Method2");
            Assert.AreEqual(validationCalls[2], "Method3");

            viewModel.Children.ValidationMethod = null;
            viewModel.Children.ChainValidationMethod
            (
                (
                    ModelCollection<ModelForCollectionPropertyChangeTest> property,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = true; validationMethod1Called++; validationCalls.Add("Method1"); }
            );
            viewModel.Children.ChainValidationMethod
            (
                (
                    ModelCollection<ModelForCollectionPropertyChangeTest> property,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = false; validationMethod2Called++; validationCalls.Add("Method2"); }
            );
            viewModel.Children.ChainValidationMethod
            (
                (
                    ModelCollection<ModelForCollectionPropertyChangeTest> property,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = true; validationMethod3Called++; validationCalls.Add("Method3"); }
            );

            validationMethod1Called = 0;
            validationMethod2Called = 0;
            validationMethod3Called = 0;
            validationCalls.Clear();

            viewModel.Children.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationMethod2Called, 1);
            Assert.AreEqual(validationMethod3Called, 0);
            Assert.AreEqual(validationCalls.Count, 2);
            Assert.AreEqual(validationCalls[0], "Method1");
            Assert.AreEqual(validationCalls[1], "Method2");
        }

        [TestMethod]
        public void IndexerTest()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child1 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child2 = Creator.Create<ModelForCollectionTesting>();

            vm.Children.Add(child1);
            vm.Children[0] = child2;

            Assert.AreEqual(vm.Children[0], child2);
            Assert.IsTrue(vm.Children.AddedModels.Contains(child2));
            Assert.AreEqual(vm.Children.Count, 1);
            Assert.AreEqual(vm.Children.AddedModelCount, 1);
            Assert.AreEqual(vm.Children.RemovedModelCount, 0);
            Assert.AreEqual(vm.Children.CommittedModelCount, 0);

            vm.Children.Add(child1);
            ModelForCollectionTesting child3 = Creator.Create<ModelForCollectionTesting>();
            vm.Children[1] = child3;

            Assert.AreEqual(vm.Children[0], child2);
            Assert.AreEqual(vm.Children[1], child3);
            Assert.AreEqual(vm.Children.Count, 2);
            Assert.AreEqual(vm.Children.AddedModelCount, 2);
            Assert.AreEqual(vm.Children.RemovedModelCount, 0);
            Assert.AreEqual(vm.Children.CommittedModelCount, 0);

            vm.Children.Commit();
            vm.Children[0] = child1;

            Assert.AreEqual(vm.Children.Count, 2);
            Assert.AreEqual(vm.Children[0], child1);
            Assert.AreEqual(vm.Children[1], child3);
            Assert.IsTrue(vm.Children.GetRemovedModels().Contains(child2));
            Assert.IsTrue(vm.Children.GetAddedModels().Contains(child1));
            Assert.IsTrue(vm.Children.GetCommittedModels().Contains(child3));

            vm.Children.Clear(true);
            vm.Children.Add(child1, true);
            vm.Children.Add(child2, true);
            vm.Children.Add(child3, true);

            ModelForCollectionTesting child4 = Creator.Create<ModelForCollectionTesting>();
            vm.Children[1] = child4;

            Assert.AreEqual(vm.Children.Count, 3);
            Assert.AreEqual(vm.Children.CommittedModelCount, 2);
            Assert.AreEqual(vm.Children.AddedModelCount, 1);
            Assert.AreEqual(vm.Children.RemovedModelCount, 1);
            Assert.IsTrue(vm.Children.CommittedModels.Contains(child1));
            Assert.IsTrue(vm.Children.CommittedModels.Contains(child3));
            Assert.IsTrue(vm.Children.AddedModels.Contains(child4));
            Assert.IsTrue(vm.Children.RemovedModels.Contains(child2));
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CommitNullTest()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Commit(null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void CommitUnParented()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Commit(Creator.Create<ModelForCollectionTesting>());
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void CommitForeignChild()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting vm2 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child = Creator.Create<ModelForCollectionTesting>();
            vm2.Children.Add(child);
            vm.Children.Commit(child);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void DoubleCommit()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(child, true);
            vm.Children.Commit(child);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddNullModel()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(null as ModelForCollectionTesting);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void AddSelfToCollection()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(vm);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void AddParentedModel()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting vm1 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child = Creator.Create<ModelForCollectionTesting>();
            vm1.Children.Add(child);
            vm.Children.Add(child);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void AddToDifferentCollectionProperty()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children2.Add(vm.Children[0]);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void AddMoreThanOnce()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Add(vm.Children[0]);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddNullArray()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(null as ModelForCollectionTesting[]);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddArrayWithNullIndex()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting[] viewModels = new ModelForCollectionTesting[]
            {
                Creator.Create<ModelForCollectionTesting>(),
                null,
                Creator.Create<ModelForCollectionTesting>()
            };
            vm.Children.Add(viewModels);
        }

        [TestMethod]
        public void AddEmptyArray()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(new ModelForCollectionTesting[] { });
        }

        [TestMethod]
        public void RemoveNull()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Remove(null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RemoveAtIncorrectIndex()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.RemoveAt(0);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void UndoRemoveNull()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.UndoRemove(null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void UndoRemoveAddedModel()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.UndoRemove(vm.Children[0]);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void UndoRemoveCommittedModel()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Commit();
            vm.Children.UndoRemove(vm.Children[0]);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void UndoRemoveForeignVM()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting vm2 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child = Creator.Create<ModelForCollectionTesting>();
            vm2.Children.Add(child, true);
            vm2.Children.Remove(child);
            vm.Children.UndoRemove(child);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SwapNullModels()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Swap(null, null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SwapNullModels2()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Swap(Creator.Create<ModelForCollectionTesting>(), null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void SwapForeignModels()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Swap(Creator.Create<ModelForCollectionTesting>(), Creator.Create<ModelForCollectionTesting>());
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void SwapForeignModels2()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting vm2 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child = Creator.Create<ModelForCollectionTesting>();
            vm2.Children.Add(child);
            vm.Children.Swap(child, Creator.Create<ModelForCollectionTesting>());
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void SwapForeignModels3()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting vm2 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child1 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child2 = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(child1);
            vm2.Children.Add(child2, true);
            vm.Children.Swap(child1, child2);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void SwapForeignModels4()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting vm2 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child1 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child2 = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(child2);
            vm2.Children.Add(child1);
            vm.Children.Swap(child1, child2);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void SwapRemovedModels()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child1 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child2 = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(child1, true);
            vm.Children.Remove(child1);
            vm.Children.Add(child2);
            vm.Children.Swap(child1, child2);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SwapIncorrectIndices()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Swap(0, 1);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SwapIncorrectIndices2()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Swap(1, 0);
        }

        [TestMethod]
        public void GetIndexOfWithNullModel()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            Assert.AreEqual(vm.Children.IndexOf(null), -1);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void GetIndexerWithInvalidIndex()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child = vm.Children[0];
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetIndexerWithNullModel()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children[0] = null;
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetIndexerWithIndexOutOfRange()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children[0] = Creator.Create<ModelForCollectionTesting>();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetIndexerWithIndexOutOfRange2()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children[1] = Creator.Create<ModelForCollectionTesting>();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SetIndexerWithIndexOutOfRange3()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children[-1] = Creator.Create<ModelForCollectionTesting>();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void CopyToWithIndexOutOfRange()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting[] vmArray = new ModelForCollectionTesting[] { };
            vm.Children.CopyTo(vmArray, 0);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void CopyToWithIndexOutOfRange2()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            ModelForCollectionTesting[] vmArray = new ModelForCollectionTesting[] { };
            vm.Children.CopyTo(vmArray, 1);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CopyToWithNullArray()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.CopyTo(null, 0);
        }

        [TestMethod]
        [ExpectedException(typeof(IndexOutOfRangeException))]
        public void CopyToWithArrayToSmall()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting[] vmArray = new ModelForCollectionTesting[1];
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.CopyTo(vmArray, 0);
        }

        [TestMethod]
        public void ReleaseObservers()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            Boolean propertyChanged1Called = false;
            Boolean collectionChanged1Called = false;

            vm.Children.PropertyChanged += delegate
            {
                propertyChanged1Called = true;
            };

            vm.Children.CollectionChanged += delegate
            {
                collectionChanged1Called = true;
            };

            Boolean propertyChanged2Called = false;
            Boolean collectionChanged2Called = false;

            vm.Children.PropertyChanged += delegate
            {
                propertyChanged2Called = true;
            };

            vm.Children.CollectionChanged += delegate
            {
                collectionChanged2Called = true;
            };

            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());

            Assert.IsTrue(propertyChanged1Called);
            Assert.IsTrue(propertyChanged2Called);
            Assert.IsTrue(collectionChanged1Called);
            Assert.IsTrue(collectionChanged2Called);

            propertyChanged1Called = false;
            propertyChanged2Called = false;
            collectionChanged1Called = false;
            collectionChanged2Called = false;

            vm.Children.ReleaseObservers();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());

            Assert.IsFalse(propertyChanged1Called);
            Assert.IsFalse(propertyChanged2Called);
            Assert.IsFalse(collectionChanged1Called);
            Assert.IsFalse(collectionChanged2Called);
        }

        [TestMethod]
        public void TestEnumerators()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());

            foreach (ModelForCollectionTesting child in vm.Children.GetAddedModels())
            {
                //Make sure iterator works
            }

            foreach (ModelForCollectionTesting child in ((IEnumerable<ModelForCollectionTesting>)vm.Children))
            {
            }

            foreach (ModelForCollectionTesting child in vm.Children)
            {
                vm.Children.Commit(child);
            }

            foreach (ModelForCollectionTesting child in vm.Children.GetCommittedModels())
            {
                //Make sure iterator works
            }

            foreach (ModelForCollectionTesting child in vm.Children.GetCommittedModels().ToArray())
            {
                vm.Children.Remove(child);
            }

            foreach (ModelForCollectionTesting child in vm.Children.GetRemovedModels())
            {
                //Make sure iterator works
            }

            foreach (ModelForCollectionTesting child in vm.Children.GetRemovedModels().ToArray())
            {
                vm.Children.UndoRemove(child);
            }
        }

        [TestMethod]
        public void TestCollectionCopyTo()
        {
            ModelForCollectionTesting viewModel = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child1 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child2 = Creator.Create<ModelForCollectionTesting>();
            ModelForCollectionTesting child3 = Creator.Create<ModelForCollectionTesting>();

            viewModel.Children.Add(child1);
            viewModel.Children.Add(child2);

            ModelForCollectionTesting[] viewModelArray = new ModelForCollectionTesting[3];
            viewModel.Children.CopyTo(viewModelArray, 0);

            Assert.AreEqual(viewModelArray[0], child1);
            Assert.AreEqual(viewModelArray[1], child2);
            Assert.IsNull(viewModelArray[2]);

            viewModel.Children.CopyTo(viewModelArray, 1);

            Assert.AreEqual(viewModelArray[0], child2);
            Assert.AreEqual(viewModelArray[1], child2);
            Assert.IsNull(viewModelArray[2]);

            viewModel.Children.Add(child3);
            viewModel.Children.CopyTo(viewModelArray, 0);

            Assert.AreEqual(viewModelArray[0], child1);
            Assert.AreEqual(viewModelArray[1], child2);
            Assert.AreEqual(viewModelArray[2], child3);

            viewModelArray = new ModelForCollectionTesting[3];

            viewModel.Children.CopyTo(viewModelArray, 2);

            Assert.AreEqual(viewModelArray[0], child3);
        }

        [TestMethod]
        public void TestAssignDefaultValue()
        {
            ModelForCollectionTesting vm = Creator.Create<ModelForCollectionTesting>();
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>());
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>(), true);
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>(), true);
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>(), true);
            vm.Children.Add(Creator.Create<ModelForCollectionTesting>(), true);
            vm.Children.RemoveAt(5);
            vm.Children.RemoveAt(4);

            vm.Children.AssignDefaultValue();

            Assert.AreEqual(vm.Children.AddedModelCount, 0);
            Assert.AreEqual(vm.Children.CommittedModelCount, 0);
            Assert.AreEqual(vm.Children.RemovedModelCount, 4);
        }

        [TestMethod]
        public void TestCollectionValidation()
        {
            ModelForCollectionTesting viewModel = Creator.Create<ModelForCollectionTesting>();
            AssertDefaultState(viewModel.Children, viewModel, "Children");

            List<String> childPropertyChanges = new List<String>();
            List<Tuple<IEnumerable<ModelForCollectionTesting>, IEnumerable<ModelForCollectionTesting>, NotifyCollectionChangedAction>> childPropertyCollectionChanges
                = new List<Tuple<IEnumerable<ModelForCollectionTesting>, IEnumerable<ModelForCollectionTesting>, NotifyCollectionChangedAction>>();

            viewModel.Children.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs args)
            {
                childPropertyChanges.Add(args.PropertyName);
            };

            List<Tuple<ModelBase, Int32, Int32>> swappedChildrenIndexes = new List<Tuple<ModelBase, Int32, Int32>>();
            List<Tuple<ModelBase, Int32>> addedChildrenIndexes = new List<Tuple<ModelBase, Int32>>();
            List<Tuple<ModelBase, Int32>> removedChildrenIndexes = new List<Tuple<ModelBase, Int32>>();

            viewModel.Children.CollectionChanged += delegate(Object sender, NotifyCollectionChangedEventArgs args)
            {
                if (args.Action == NotifyCollectionChangedAction.Replace)
                {
                    swappedChildrenIndexes.Add(new Tuple<ModelBase, Int32, Int32>(args.NewItems.Cast<ModelForCollectionTesting>().ElementAt(0), args.NewStartingIndex, args.OldStartingIndex));
                }
                else if (args.Action == NotifyCollectionChangedAction.Add)
                {
                    IEnumerable<ModelForCollectionTesting> elements = args.NewItems.Cast<ModelForCollectionTesting>();

                    for (Int32 index = 0; index < elements.Count(); index++)
                    {
                        addedChildrenIndexes.Add(new Tuple<ModelBase, Int32>(elements.ElementAt(index), args.NewStartingIndex));
                    }
                }
                else if (args.Action == NotifyCollectionChangedAction.Remove)
                {
                    IEnumerable<ModelForCollectionTesting> elements = args.OldItems.Cast<ModelForCollectionTesting>();

                    for (Int32 index = 0; index < elements.Count(); index++)
                    {
                        removedChildrenIndexes.Add(new Tuple<ModelBase, Int32>(elements.ElementAt(index), args.OldStartingIndex));
                    }
                }

                childPropertyCollectionChanges.Add
                (
                    new Tuple<IEnumerable<ModelForCollectionTesting>, IEnumerable<ModelForCollectionTesting>, NotifyCollectionChangedAction>
                    (
                        args.NewItems != null ? args.NewItems.Cast<ModelForCollectionTesting>() as IEnumerable<ModelForCollectionTesting> : null,
                        args.OldItems != null ? args.OldItems.Cast<ModelForCollectionTesting>() as IEnumerable<ModelForCollectionTesting> : null,
                        args.Action
                    )
                );
            };

            viewModel.Children.Validate();
            Assert.IsFalse(viewModel.Children.IsInvalid);

            IEnumerable<ValidationError> errors = null;
            Boolean isValid = true;
            Int32 validationMethodCallCount = 0;

            viewModel.Children.ValidationMethod = delegate
            (
                ModelCollection<ModelForCollectionTesting> property,
                ref IEnumerable<ValidationError> validationErrors,
                ref Boolean validationResult
            )
            {
                validationErrors = errors;
                validationResult = isValid;
                validationMethodCallCount++;
            };

            viewModel.Children.Validate();
            Assert.IsFalse(viewModel.Children.IsInvalid);

            Assert.AreEqual(validationMethodCallCount, 1);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            viewModel.Children.Add(Creator.Create<ModelForCollectionTesting>());

            Assert.AreEqual(validationMethodCallCount, 2);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.AreEqual(viewModel.Children.ValidationErrors, errors);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();

            isValid = false;
            errors = new List<ValidationError>();

            viewModel.Children.Add(Creator.Create<ModelForCollectionTesting>());

            Assert.AreEqual(validationMethodCallCount, 1);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.AreEqual(viewModel.Children.ValidationErrors, errors);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ValidationErrors");
            Assert.AreEqual(childPropertyChanges[4], "IsInvalid");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[1]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();

            isValid = true;
            errors = new List<ValidationError>();
            viewModel.Children.Insert(0, Creator.Create<ModelForCollectionTesting>());

            Assert.AreEqual(validationMethodCallCount, 1);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.IsNull(viewModel.Children.ValidationErrors);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ValidationErrors");
            Assert.AreEqual(childPropertyChanges[4], "IsInvalid");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes[0].Item1, viewModel.Children[0]);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Insert(0, Creator.Create<ModelForCollectionTesting>(), true);

            Assert.AreEqual(validationMethodCallCount, 1);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.IsNull(viewModel.Children.ValidationErrors);
            Assert.AreEqual(childPropertyChanges.Count, 4);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsCommittedModels");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();

            isValid = false;
            ModelForCollectionTesting[] childrenToAdd = new ModelForCollectionTesting[] { Creator.Create<ModelForCollectionTesting>(), Creator.Create<ModelForCollectionTesting>() };
            viewModel.Children.Add(childrenToAdd, true);

            Assert.AreEqual(validationMethodCallCount, 1);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.AreEqual(viewModel.Children.ValidationErrors, errors);
            Assert.AreEqual(childPropertyChanges.Count, 8);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[6], "ValidationErrors");
            Assert.AreEqual(childPropertyChanges[7], "IsInvalid");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Remove(childrenToAdd[0]);
            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Commit();

            Assert.AreEqual(validationMethodCallCount, 0);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.AreEqual(viewModel.Children.ValidationErrors, errors);
            Assert.AreEqual(childPropertyChanges.Count, 17);
            Assert.AreEqual(childPropertyChanges[0], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[2], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[3], "AddedModels");
            Assert.AreEqual(childPropertyChanges[4], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[6], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[7], "AddedModels");
            Assert.AreEqual(childPropertyChanges[8], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[9], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[10], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[11], "AddedModels");
            Assert.AreEqual(childPropertyChanges[12], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[13], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[14], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[15], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[16], "IsDirty");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();

            isValid = false;
            errors = null;
            viewModel.Children.RemoveAt(1);

            Assert.AreEqual(validationMethodCallCount, 1);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.AreEqual(viewModel.Children.ValidationErrors, errors);
            Assert.AreEqual(childPropertyChanges.Count, 8);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[7], "ValidationErrors");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes[0].Item1, viewModel.Children.RemovedModels.ElementAt(0));
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 1);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), viewModel.Children.RemovedModels.ElementAt(0));
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            viewModel.Children.Add(Creator.Create<ModelForCollectionTesting>());
            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();

            errors = new List<ValidationError>();
            (errors as List<ValidationError>).Add(new ValidationError());
            viewModel.Children.Clear(true);

            Assert.AreEqual(validationMethodCallCount, 1);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.AreEqual(viewModel.Children.ValidationErrors, errors);
            Assert.AreEqual(childPropertyChanges.Count, 22);
            Assert.AreEqual(childPropertyChanges[0], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[2], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[6], "Count");
            Assert.AreEqual(childPropertyChanges[7], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[8], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[9], "Count");
            Assert.AreEqual(childPropertyChanges[10], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[11], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[12], "Count");
            Assert.AreEqual(childPropertyChanges[13], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[14], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[15], "ContainsCommittedModels");
            Assert.AreEqual(childPropertyChanges[16], "Count");
            Assert.AreEqual(childPropertyChanges[17], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[18], "AddedModels");
            Assert.AreEqual(childPropertyChanges[19], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[20], "IsDirty");
            Assert.AreEqual(childPropertyChanges[21], "ValidationErrors");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Add
            (
                new ModelForCollectionTesting[]
                {
                    Creator.Create<ModelForCollectionTesting>(),
                    Creator.Create<ModelForCollectionTesting>(),
                    Creator.Create<ModelForCollectionTesting>(),
                    Creator.Create<ModelForCollectionTesting>()
                },
                true
            );

            ModelForCollectionTesting removedChild = viewModel.Children[1];
            viewModel.Children.Remove(removedChild);
            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();
            isValid = true;
            viewModel.Children.UndoRemove(removedChild);

            Assert.AreEqual(validationMethodCallCount, 1);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.IsNull(viewModel.Children.ValidationErrors);
            Assert.AreEqual(childPropertyChanges.Count, 9);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[5], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[6], "IsDirty");
            Assert.AreEqual(childPropertyChanges[7], "ValidationErrors");
            Assert.AreEqual(childPropertyChanges[8], "IsInvalid");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), removedChild);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            viewModel.Children.RemoveAt(0);
            viewModel.Children.Add(Creator.Create<ModelForCollectionTesting>());

            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();
            isValid = false;
            viewModel.Children.Reset();

            Assert.AreEqual(validationMethodCallCount, 1);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.AreEqual(viewModel.Children.ValidationErrors, errors);
            Assert.AreEqual(childPropertyChanges.Count, 13);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[5], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[6], "Count");
            Assert.AreEqual(childPropertyChanges[7], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[8], "AddedModels");
            Assert.AreEqual(childPropertyChanges[9], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[10], "IsDirty");
            Assert.AreEqual(childPropertyChanges[11], "ValidationErrors");
            Assert.AreEqual(childPropertyChanges[12], "IsInvalid");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            validationMethodCallCount = 0;
            childPropertyChanges.Clear();
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Swap(1, 3);

            Assert.AreEqual(validationMethodCallCount, 0);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(swappedChildrenIndexes.Count, 2);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 2);

            swappedChildrenIndexes.Clear();
            childPropertyCollectionChanges.Clear();
            isValid = true;
            viewModel.Children[1] = Creator.Create<ModelForCollectionTesting>();

            Assert.AreEqual(validationMethodCallCount, 2);
            Assert.AreEqual(viewModel.Children.IsInvalid, !isValid);
            Assert.IsNull(viewModel.Children.ValidationErrors);
            Assert.AreEqual(childPropertyChanges.Count, 13);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "ValidationErrors");
            Assert.AreEqual(childPropertyChanges[6], "IsInvalid");
            Assert.AreEqual(childPropertyChanges[7], "Count");
            Assert.AreEqual(childPropertyChanges[8], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[9], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[10], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[11], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[12], "CommittedModels");
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 1);
            Assert.AreEqual(addedChildrenIndexes.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);
            Assert.IsNull(childPropertyCollectionChanges[1].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item3, NotifyCollectionChangedAction.Remove);
        }

        [TestMethod]
        public void TestCollections()
        {
            var viewModel = Creator.Create<ModelForCollectionTesting>();
            AssertDefaultState(viewModel.Children, viewModel, "Children");

            List<String> childPropertyChanges = new List<String>();
            List<Tuple<IEnumerable<ModelForCollectionTesting>, IEnumerable<ModelForCollectionTesting>, NotifyCollectionChangedAction>> childPropertyCollectionChanges
                = new List<Tuple<IEnumerable<ModelForCollectionTesting>, IEnumerable<ModelForCollectionTesting>, NotifyCollectionChangedAction>>();

            viewModel.Children.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs args)
            {
                childPropertyChanges.Add(args.PropertyName);
            };

            List<Tuple<ModelBase, ModelBase, Int32>> swappedChildrenIndexes = new List<Tuple<ModelBase, ModelBase, Int32>>();
            List<Tuple<ModelBase, Int32>> addedChildrenIndexes = new List<Tuple<ModelBase, Int32>>();
            List<Tuple<ModelBase, Int32>> removedChildrenIndexes = new List<Tuple<ModelBase, Int32>>();

            viewModel.Children.CollectionChanged += delegate(Object sender, NotifyCollectionChangedEventArgs args)
            {
                if (args.Action == NotifyCollectionChangedAction.Replace)
                {
                    swappedChildrenIndexes.Add(new Tuple<ModelBase, ModelBase, Int32>(args.NewItems.Cast<ModelForCollectionTesting>().ElementAt(0), args.OldItems.Cast<ModelForCollectionTesting>().ElementAt(0), args.NewStartingIndex));
                }
                else if (args.Action == NotifyCollectionChangedAction.Add)
                {
                    IEnumerable<ModelForCollectionTesting> elements = args.NewItems.Cast<ModelForCollectionTesting>();

                    for (Int32 index = 0; index < elements.Count(); index++)
                    {
                        addedChildrenIndexes.Add(new Tuple<ModelBase, Int32>(elements.ElementAt(index), args.NewStartingIndex));
                    }
                }
                else if (args.Action == NotifyCollectionChangedAction.Remove)
                {
                    IEnumerable<ModelForCollectionTesting> elements = args.OldItems.Cast<ModelForCollectionTesting>();

                    for (Int32 index = 0; index < elements.Count(); index++)
                    {
                        removedChildrenIndexes.Add(new Tuple<ModelBase, Int32>(elements.ElementAt(index), args.OldStartingIndex));
                    }
                }

                childPropertyCollectionChanges.Add
                (
                    new Tuple<IEnumerable<ModelForCollectionTesting>, IEnumerable<ModelForCollectionTesting>, NotifyCollectionChangedAction>
                    (
                        args.NewItems != null ? args.NewItems.Cast<ModelForCollectionTesting>() as IEnumerable<ModelForCollectionTesting> : null,
                        args.OldItems != null ? args.OldItems.Cast<ModelForCollectionTesting>() as IEnumerable<ModelForCollectionTesting> : null,
                        args.Action
                    )
                );
            };

            var child1 = Creator.Create<ModelForCollectionTesting>();
            viewModel.Children.Add(child1);

            VerifyChildAddedToCollection(viewModel.Children, child1);
            VerifyCollection(viewModel.Children, viewModel, 1, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            Assert.IsFalse(viewModel.Children.Remove(null));
            Assert.IsFalse(viewModel.Children.Remove(Creator.Create<ModelForCollectionTesting>()));
            Assert.IsTrue(viewModel.Children.Remove(child1));
            Assert.IsFalse(viewModel.Children.Remove(child1));

            VerifyChildPurgedFromCollection(viewModel.Children, child1);
            VerifyCollection(viewModel.Children, viewModel, 0, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), child1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            var child2 = Creator.Create<ModelForCollectionTesting>();
            viewModel.Children.Add(child2);

            VerifyChildAddedToCollection(viewModel.Children, child2);
            VerifyCollection(viewModel.Children, viewModel, 1, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(viewModel.Children[0], child2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Add(child1);

            VerifyChildAddedToCollection(viewModel.Children, child1);
            VerifyCollection(viewModel.Children, viewModel, 2, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(viewModel.Children[1], child1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[1]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            Assert.IsFalse(viewModel.Children.Remove(null));
            Assert.IsFalse(viewModel.Children.Remove(Creator.Create<ModelForCollectionTesting>()));
            Assert.IsTrue(viewModel.Children.Remove(child2));
            Assert.IsFalse(viewModel.Children.Remove(child2));

            VerifyChildPurgedFromCollection(viewModel.Children, child2);
            VerifyCollection(viewModel.Children, viewModel, 1, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), child2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Add(child2);

            VerifyChildAddedToCollection(viewModel.Children, child2);
            VerifyCollection(viewModel.Children, viewModel, 2, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(viewModel.Children[1], child2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[1]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Commit(child2);

            VerifyCollection(viewModel.Children, viewModel, 1, 0, 1);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[2], "ContainsCommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "AddedModels");
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Commit(child1);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 2);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[2], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[3], "AddedModels");
            Assert.AreEqual(childPropertyChanges[4], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[5], "IsDirty");
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            Assert.IsTrue(viewModel.Children.Remove(child1));

            VerifyCollection(viewModel.Children, viewModel, 0, 1, 1);
            Assert.AreEqual(childPropertyChanges.Count, 7);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), child1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.UndoRemove(child1);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 2);
            Assert.AreEqual(childPropertyChanges.Count, 7);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[5], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[6], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            Assert.IsTrue(viewModel.Children.Remove(child2));

            VerifyCollection(viewModel.Children, viewModel, 0, 1, 1);
            Assert.AreEqual(childPropertyChanges.Count, 7);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), child2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            Assert.IsTrue(viewModel.Children.Remove(child1));

            VerifyCollection(viewModel.Children, viewModel, 0, 2, 0);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[5], "ContainsCommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), child1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.UndoRemove(child2);

            VerifyCollection(viewModel.Children, viewModel, 0, 1, 1);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsCommittedModels");
            Assert.AreEqual(childPropertyChanges[4], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "RemovedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child2);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Commit(child1);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 1);
            VerifyChildPurgedFromCollection(viewModel.Children, child1);
            Assert.AreEqual(childPropertyChanges.Count, 4);
            Assert.AreEqual(childPropertyChanges[0], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[2], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "IsDirty");
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            Assert.IsTrue(viewModel.Children.Remove(child2));

            VerifyCollection(viewModel.Children, viewModel, 0, 1, 0);
            Assert.AreEqual(childPropertyChanges.Count, 8);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[7], "ContainsCommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), child2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Commit(child2);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 0);
            VerifyChildPurgedFromCollection(viewModel.Children, child2);
            Assert.AreEqual(childPropertyChanges.Count, 4);
            Assert.AreEqual(childPropertyChanges[0], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[2], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "IsDirty");
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Add(child1);

            VerifyChildAddedToCollection(viewModel.Children, child1);
            VerifyCollection(viewModel.Children, viewModel, 1, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Commit(child1);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 1);
            Assert.AreEqual(childPropertyChanges.Count, 7);
            Assert.AreEqual(childPropertyChanges[0], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[2], "ContainsCommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "AddedModels");
            Assert.AreEqual(childPropertyChanges[5], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[6], "IsDirty");
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Add(child2, true);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 2);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child2);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            Assert.IsTrue(viewModel.Children.Remove(child1, true));

            VerifyChildPurgedFromCollection(viewModel.Children, child1);
            VerifyCollection(viewModel.Children, viewModel, 0, 0, 1);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), child1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            Assert.IsFalse(viewModel.Children.Remove(child1, true));
            Assert.IsTrue(viewModel.Children.Remove(child2, false));
            Assert.IsFalse(viewModel.Children.Remove(child2, false));

            VerifyCollection(viewModel.Children, viewModel, 0, 1, 0);
            Assert.AreEqual(childPropertyChanges.Count, 8);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[7], "ContainsCommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), child2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Add(child1, false);

            VerifyCollection(viewModel.Children, viewModel, 1, 1, 0);
            Assert.AreEqual(childPropertyChanges.Count, 4);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();

            var child3 = Creator.Create<ModelForCollectionTesting>();
            var child4 = Creator.Create<ModelForCollectionTesting>();
            viewModel.Children.Add(child3, true);

            Assert.AreEqual(addedChildrenIndexes[0].Item1, child3);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear();

            VerifyCollection(viewModel.Children, viewModel, 0, 2, 0);
            Assert.AreEqual(childPropertyChanges.Count, 10);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "Count");
            Assert.AreEqual(childPropertyChanges[5], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[7], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[8], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[9], "ContainsCommittedModels");
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear();
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear(false);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            viewModel.Children.UndoRemove(child2);
            VerifyCollection(viewModel.Children, viewModel, 0, 1, 1);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsCommittedModels");
            Assert.AreEqual(childPropertyChanges[4], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "RemovedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child2);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.UndoRemove(child3);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 2);
            Assert.AreEqual(childPropertyChanges.Count, 7);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[5], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[6], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child3);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child3);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear(true);
            VerifyChildPurgedFromCollection(viewModel.Children, child1);
            VerifyChildPurgedFromCollection(viewModel.Children, child2);
            VerifyCollection(viewModel.Children, viewModel, 0, 0, 0);

            Assert.AreEqual(childPropertyChanges.Count, 7);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[6], "ContainsCommittedModels");
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            removedChildrenIndexes.Clear();

            viewModel.Children.Add(child1, true);

            Assert.AreEqual(addedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            addedChildrenIndexes.Clear();

            viewModel.Children.Add(child2);

            Assert.AreEqual(addedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            addedChildrenIndexes.Clear();

            viewModel.Children.Add(child3, false);

            Assert.AreEqual(addedChildrenIndexes[0].Item1, child3);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, viewModel.Children.Count - 1);
            addedChildrenIndexes.Clear();

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear(false);

            VerifyChildPurgedFromCollection(viewModel.Children, child2);
            VerifyChildPurgedFromCollection(viewModel.Children, child3);
            VerifyCollection(viewModel.Children, viewModel, 0, 1, 0);
            Assert.AreEqual(childPropertyChanges.Count, 14);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[4], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[6], "ContainsCommittedModels");
            Assert.AreEqual(childPropertyChanges[7], "Count");
            Assert.AreEqual(childPropertyChanges[8], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[9], "AddedModels");
            Assert.AreEqual(childPropertyChanges[10], "Count");
            Assert.AreEqual(childPropertyChanges[11], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[12], "AddedModels");
            Assert.AreEqual(childPropertyChanges[13], "ContainsAddedModels");
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear(false);

            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            viewModel.Children.Commit(child1);

            Assert.AreEqual(childPropertyChanges.Count, 4);
            Assert.AreEqual(childPropertyChanges[0], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[2], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "IsDirty");
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Insert(0, child1);

            VerifyCollection(viewModel.Children, viewModel, 1, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Insert(0, child2);

            Assert.AreEqual(viewModel.Children[0], child2);
            Assert.AreEqual(viewModel.Children[1], child1);
            VerifyCollection(viewModel.Children, viewModel, 2, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child2);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Insert(1, child3);

            Assert.AreEqual(viewModel.Children[0], child2);
            Assert.AreEqual(viewModel.Children[1], child3);
            Assert.AreEqual(viewModel.Children[2], child1);
            VerifyCollection(viewModel.Children, viewModel, 3, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child3);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child3);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Insert(3, child4);

            Assert.AreEqual(viewModel.Children[0], child2);
            Assert.AreEqual(viewModel.Children[1], child3);
            Assert.AreEqual(viewModel.Children[2], child1);
            Assert.AreEqual(viewModel.Children[3], child4);
            VerifyCollection(viewModel.Children, viewModel, 4, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child4);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 3);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child4);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            var child5 = Creator.Create<ModelForCollectionTesting>();
            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Insert(0, child5, true);

            Assert.AreEqual(viewModel.Children[0], child5);
            Assert.AreEqual(viewModel.Children[1], child2);
            Assert.AreEqual(viewModel.Children[2], child3);
            Assert.AreEqual(viewModel.Children[3], child1);
            Assert.AreEqual(viewModel.Children[4], child4);
            VerifyCollection(viewModel.Children, viewModel, 4, 0, 1);
            Assert.AreEqual(childPropertyChanges.Count, 4);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsCommittedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child5);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child5);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            var child6 = Creator.Create<ModelForCollectionTesting>();
            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Insert(5, child6, true);

            Assert.AreEqual(viewModel.Children[0], child5);
            Assert.AreEqual(viewModel.Children[1], child2);
            Assert.AreEqual(viewModel.Children[2], child3);
            Assert.AreEqual(viewModel.Children[3], child1);
            Assert.AreEqual(viewModel.Children[4], child4);
            Assert.AreEqual(viewModel.Children[5], child6);
            VerifyCollection(viewModel.Children, viewModel, 4, 0, 2);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child6);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 5);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child6);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            var child7 = Creator.Create<ModelForCollectionTesting>();
            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Insert(2, child7, true);

            Assert.AreEqual(viewModel.Children[0], child5);
            Assert.AreEqual(viewModel.Children[1], child2);
            Assert.AreEqual(viewModel.Children[2], child7);
            Assert.AreEqual(viewModel.Children[3], child3);
            Assert.AreEqual(viewModel.Children[4], child1);
            Assert.AreEqual(viewModel.Children[5], child4);
            Assert.AreEqual(viewModel.Children[6], child6);
            VerifyCollection(viewModel.Children, viewModel, 4, 0, 3);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child7);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 2);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), child7);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);

            addedChildrenIndexes.Clear();
            viewModel.Children.Remove(child6);

            Assert.AreEqual(removedChildrenIndexes[0].Item1, child6);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 6);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Commit();

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 6);
            Assert.AreEqual(childPropertyChanges.Count, 21);
            Assert.AreEqual(childPropertyChanges[0], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[2], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[3], "AddedModels");
            Assert.AreEqual(childPropertyChanges[4], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[6], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[7], "AddedModels");
            Assert.AreEqual(childPropertyChanges[8], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[9], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[10], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[11], "AddedModels");
            Assert.AreEqual(childPropertyChanges[12], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[13], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[14], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[15], "AddedModels");
            Assert.AreEqual(childPropertyChanges[16], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[17], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[18], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[19], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[20], "IsDirty");
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            var child8 = Creator.Create<ModelForCollectionTesting>();
            var child9 = Creator.Create<ModelForCollectionTesting>();
            viewModel.Children.Add(child8);
            viewModel.Children.Add(child9);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();

            var removedChild = viewModel.Children[0];
            viewModel.Children.RemoveAt(0);

            VerifyCollection(viewModel.Children, viewModel, 2, 1, 5);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[4], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, removedChild);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), removedChild);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            removedChild = viewModel.Children.AddedModels.ElementAt(0);
            Int32 removedChildIndex = viewModel.Children.IndexOf(removedChild);
            viewModel.Children.RemoveAt(removedChildIndex);

            VerifyCollection(viewModel.Children, viewModel, 1, 1, 5);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, removedChild);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, removedChildIndex);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), removedChild);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            viewModel.Children.Commit();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            removedChildIndex = viewModel.Children.Count - 1;
            removedChild = viewModel.Children[removedChildIndex];
            viewModel.Children.RemoveAt(viewModel.Children.Count - 1, true);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 5);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, removedChild);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, removedChildIndex);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), removedChild);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            viewModel.Children.Commit();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            removedChildIndex = 2;
            removedChild = viewModel.Children[removedChildIndex];
            viewModel.Children.RemoveAt(viewModel.Children.IndexOf(removedChild), false);

            VerifyCollection(viewModel.Children, viewModel, 0, 1, 4);
            Assert.AreEqual(childPropertyChanges.Count, 7);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, removedChild);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, removedChildIndex);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), removedChild);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            removedChildIndex = 1;
            removedChild = viewModel.Children[removedChildIndex];
            viewModel.Children.RemoveAt(removedChildIndex, false);

            VerifyCollection(viewModel.Children, viewModel, 0, 2, 3);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "CommittedModels");
            Assert.AreEqual(removedChildrenIndexes[0].Item1, removedChild);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, removedChildIndex);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), removedChild);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Remove);

            removedChildrenIndexes.Clear();
            var swapChildA = viewModel.Children[0];
            var swapChildB = viewModel.Children[viewModel.Children.Count - 1];
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Swap(swapChildA, swapChildB);

            VerifyCollection(viewModel.Children, viewModel, 0, 2, 3);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(swappedChildrenIndexes[0].Item1, swapChildB);
            Assert.AreEqual(swappedChildrenIndexes[0].Item2, swapChildA);
            Assert.AreEqual(swappedChildrenIndexes[0].Item3, 0);
            Assert.AreEqual(swappedChildrenIndexes[1].Item1, swapChildA);
            Assert.AreEqual(swappedChildrenIndexes[1].Item2, swapChildB);
            Assert.AreEqual(swappedChildrenIndexes[1].Item3, 2);
            Assert.AreEqual(viewModel.Children.IndexOf(swapChildA), viewModel.Children.Count - 1);
            Assert.AreEqual(viewModel.Children.IndexOf(swapChildB), 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), swapChildB);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), swapChildA);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Replace);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item1.ElementAt(0), swapChildA);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.ElementAt(0), swapChildB);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item3, NotifyCollectionChangedAction.Replace);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();
            viewModel.Children.Swap(swapChildB, swapChildA);

            VerifyCollection(viewModel.Children, viewModel, 0, 2, 3);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(swappedChildrenIndexes[0].Item1, swapChildA);
            Assert.AreEqual(swappedChildrenIndexes[0].Item2, swapChildB);
            Assert.AreEqual(swappedChildrenIndexes[0].Item3, 0);
            Assert.AreEqual(swappedChildrenIndexes[1].Item1, swapChildB);
            Assert.AreEqual(swappedChildrenIndexes[1].Item2, swapChildA);
            Assert.AreEqual(swappedChildrenIndexes[1].Item3, 2);
            Assert.AreEqual(viewModel.Children.IndexOf(swapChildB), viewModel.Children.Count - 1);
            Assert.AreEqual(viewModel.Children.IndexOf(swapChildA), 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), swapChildA);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), swapChildB);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Replace);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item1.ElementAt(0), swapChildB);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.ElementAt(0), swapChildA);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item3, NotifyCollectionChangedAction.Replace);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();
            viewModel.Children.Swap(swapChildB, swapChildB);

            VerifyCollection(viewModel.Children, viewModel, 0, 2, 3);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            var swapChildC = viewModel.Children[1];
            viewModel.Children.Swap(swapChildA, swapChildC);

            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(swappedChildrenIndexes[0].Item1, swapChildC);
            Assert.AreEqual(swappedChildrenIndexes[0].Item2, swapChildA);
            Assert.AreEqual(swappedChildrenIndexes[0].Item3, 0);
            Assert.AreEqual(swappedChildrenIndexes[1].Item1, swapChildA);
            Assert.AreEqual(swappedChildrenIndexes[1].Item2, swapChildC);
            Assert.AreEqual(swappedChildrenIndexes[1].Item3, 1);
            Assert.AreEqual(viewModel.Children.IndexOf(swapChildA), 1);
            Assert.AreEqual(viewModel.Children.IndexOf(swapChildC), 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), swapChildC);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), swapChildA);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Replace);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item1.ElementAt(0), swapChildA);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.ElementAt(0), swapChildC);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item3, NotifyCollectionChangedAction.Replace);

            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();
            viewModel.Children.Swap(viewModel.Children.IndexOf(swapChildA), viewModel.Children.IndexOf(swapChildC));

            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(swappedChildrenIndexes[0].Item1, swapChildC);
            Assert.AreEqual(swappedChildrenIndexes[0].Item2, swapChildA);
            Assert.AreEqual(swappedChildrenIndexes[0].Item3, 1);
            Assert.AreEqual(swappedChildrenIndexes[1].Item1, swapChildA);
            Assert.AreEqual(swappedChildrenIndexes[1].Item2, swapChildC);
            Assert.AreEqual(swappedChildrenIndexes[1].Item3, 0);
            Assert.AreEqual(viewModel.Children.IndexOf(swapChildA), 0);
            Assert.AreEqual(viewModel.Children.IndexOf(swapChildC), 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), swapChildC);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item2.ElementAt(0), swapChildA);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Replace);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item1.ElementAt(0), swapChildA);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.ElementAt(0), swapChildC);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item3, NotifyCollectionChangedAction.Replace);

            Assert.IsTrue(viewModel.Children.Contains(viewModel.Children.CommittedModels.ElementAt(0)));
            Assert.IsTrue(viewModel.Children.Contains(viewModel.Children.CommittedModels.ElementAt(1)));
            Assert.IsTrue(viewModel.Children.Contains(viewModel.Children.CommittedModels.ElementAt(2)));

            var child10 = Creator.Create<ModelForCollectionTesting>();
            viewModel.Children.Add(child10);
            Assert.IsTrue(viewModel.Children.Contains(viewModel.Children.AddedModels.ElementAt(0)));

            Assert.IsFalse(viewModel.Children.Contains(viewModel.Children.RemovedModels.ElementAt(0)));
            Assert.IsFalse(viewModel.Children.Contains(viewModel.Children.RemovedModels.ElementAt(1)));
            Assert.IsFalse(viewModel.Children.Contains(null));
            Assert.IsFalse(viewModel.Children.Contains(Creator.Create<ModelForCollectionTesting>()));

            viewModel.Children.Clear();
            viewModel.Children.Commit();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();

            viewModel.Children.Add(new ModelForCollectionTesting[] { });

            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);

            viewModel.Children.Add(new ModelForCollectionTesting[] { child1, child2 });
            VerifyChildAddedToCollection(viewModel.Children, child1);
            VerifyChildAddedToCollection(viewModel.Children, child2);
            VerifyCollection(viewModel.Children, viewModel, 2, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 8);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "Count");
            Assert.AreEqual(childPropertyChanges[6], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[7], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            viewModel.Children.Add(new ModelForCollectionTesting[] { child3, child4 });
            VerifyChildAddedToCollection(viewModel.Children, child3);
            VerifyChildAddedToCollection(viewModel.Children, child4);
            VerifyCollection(viewModel.Children, viewModel, 4, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            Int32 currentChildrenCount = viewModel.Children.Count;
            viewModel.Children.Add(new ModelForCollectionTesting[] { child5, child6 });
            VerifyChildAddedToCollection(viewModel.Children, child5);
            VerifyChildAddedToCollection(viewModel.Children, child6);
            VerifyCollection(viewModel.Children, viewModel, 6, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            viewModel.Children.Add(new ModelForCollectionTesting[] { child7 });
            VerifyChildAddedToCollection(viewModel.Children, child7);
            VerifyCollection(viewModel.Children, viewModel, 7, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            viewModel.Children.Add(new ModelForCollectionTesting[] { child8, child9 }, true);
            VerifyChildCommittedToCollection(viewModel.Children, child8);
            VerifyChildCommittedToCollection(viewModel.Children, child9);
            VerifyCollection(viewModel.Children, viewModel, 7, 0, 2);
            Assert.AreEqual(childPropertyChanges.Count, 7);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsCommittedModels");
            Assert.AreEqual(childPropertyChanges[4], "Count");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            addedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            viewModel.Children.Add(new ModelForCollectionTesting[] { child10 }, false);
            VerifyChildAddedToCollection(viewModel.Children, child10);
            VerifyCollection(viewModel.Children, viewModel, 8, 0, 2);
            Assert.AreEqual(childPropertyChanges.Count, 3);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Clear(true);
            viewModel.Children.Add(child1);
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            viewModel.Children[0] = child2;
            VerifyChildPurgedFromCollection(viewModel.Children, child1);
            VerifyChildAddedToCollection(viewModel.Children, child2);
            VerifyCollection(viewModel.Children, viewModel, 1, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);
            Assert.IsNull(childPropertyCollectionChanges[1].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.ElementAt(0), child1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item3, NotifyCollectionChangedAction.Remove);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            viewModel.Children[0] = child1;
            VerifyChildAddedToCollection(viewModel.Children, child1);
            VerifyChildPurgedFromCollection(viewModel.Children, child2);
            VerifyCollection(viewModel.Children, viewModel, 1, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);
            Assert.IsNull(childPropertyCollectionChanges[1].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.ElementAt(0), child2);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item3, NotifyCollectionChangedAction.Remove);

            viewModel.Children.Commit();
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            viewModel.Children[0] = child2;
            VerifyChildRemovedFromCollection(viewModel.Children, child1);
            VerifyChildAddedToCollection(viewModel.Children, child2);
            VerifyCollection(viewModel.Children, viewModel, 1, 1, 0);
            Assert.AreEqual(childPropertyChanges.Count, 12);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "Count");
            Assert.AreEqual(childPropertyChanges[6], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[7], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[8], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[9], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[10], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[11], "ContainsCommittedModels");
            Assert.AreEqual(addedChildrenIndexes[0].Item1, child2);
            Assert.AreEqual(addedChildrenIndexes[0].Item2, 0);
            Assert.AreEqual(removedChildrenIndexes[0].Item1, child1);
            Assert.AreEqual(removedChildrenIndexes[0].Item2, 1);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item1.ElementAt(0), viewModel.Children[0]);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Add);
            Assert.IsNull(childPropertyCollectionChanges[1].Item1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.Count(), 1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item2.ElementAt(0), child1);
            Assert.AreEqual(childPropertyCollectionChanges[1].Item3, NotifyCollectionChangedAction.Remove);

            viewModel.Children.Add(child3, true);
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            viewModel.Children.Reset();

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 2);
            Assert.AreEqual(childPropertyChanges.Count, 11);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[5], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[6], "Count");
            Assert.AreEqual(childPropertyChanges[7], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[8], "AddedModels");
            Assert.AreEqual(childPropertyChanges[9], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[10], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            swappedChildrenIndexes.Clear();

            viewModel.Children.Reset();

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 2);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);
            Assert.AreEqual(swappedChildrenIndexes.Count, 0);

            child1.TagName = "Child1";
            child2.TagName = "Child2";
            child3.TagName = "Child3";
            child4.TagName = "Child4";
            child5.TagName = "Child5";
            child6.TagName = "Child6";
            child7.TagName = "Child7";
            child8.TagName = "Child8";

            viewModel.Children.Clear();
            viewModel.Children.Add(child4);
            viewModel.Children.Add(child6, true);
            viewModel.Children.Add(child5);
            viewModel.Children.Add(child7, true);
            viewModel.Children.Add(child8);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Reset();

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 4);
            Assert.AreEqual(childPropertyChanges.Count, 22);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[4], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[5], "Count");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[7], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[8], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[9], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[10], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[11], "Count");
            Assert.AreEqual(childPropertyChanges[12], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[13], "AddedModels");
            Assert.AreEqual(childPropertyChanges[14], "Count");
            Assert.AreEqual(childPropertyChanges[15], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[16], "AddedModels");
            Assert.AreEqual(childPropertyChanges[17], "Count");
            Assert.AreEqual(childPropertyChanges[18], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[19], "AddedModels");
            Assert.AreEqual(childPropertyChanges[20], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[21], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Clear(true);
            viewModel.Children.Add(child1);
            viewModel.Children.Add(child2, true);
            viewModel.Children.Add(child3);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Reset();

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 1);
            Assert.AreEqual(childPropertyChanges.Count, 8);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "AddedModels");
            Assert.AreEqual(childPropertyChanges[6], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[7], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Clear(true);
            viewModel.Children.Add(child1);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Reset();

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Clear(true);
            viewModel.Children.Add(child1, true);
            viewModel.Children.Clear();

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Reset();

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 1);
            Assert.AreEqual(childPropertyChanges.Count, 8);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsCommittedModels");
            Assert.AreEqual(childPropertyChanges[4], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[6], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[7], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Clear(true);
            viewModel.Children.Add(child1);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Reset();

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 5);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Clear(true);
            viewModel.Children.Add(child1, true);
            viewModel.Children.Add(child2, true);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.Reset();

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 2);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            viewModel.Children.Remove(child1);
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear(true);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 8);
            Assert.AreEqual(childPropertyChanges[0], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[2], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[3], "IsDirty");
            Assert.AreEqual(childPropertyChanges[4], "Count");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[7], "ContainsCommittedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Remove(child1);
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear(true);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            viewModel.Children.Add(child1);
            viewModel.Children.Add(child2);
            viewModel.Children.Add(child3, true);
            viewModel.Children.Add(child4, true);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear();

            VerifyCollection(viewModel.Children, viewModel, 0, 2, 0);
            Assert.AreEqual(childPropertyChanges.Count, 21);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "AddedModels");
            Assert.AreEqual(childPropertyChanges[6], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[7], "IsDirty");
            Assert.AreEqual(childPropertyChanges[8], "Count");
            Assert.AreEqual(childPropertyChanges[9], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[10], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[11], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[12], "IsDirty");
            Assert.AreEqual(childPropertyChanges[13], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[14], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[15], "Count");
            Assert.AreEqual(childPropertyChanges[16], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[17], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[18], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[19], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[20], "ContainsCommittedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Clear();

            VerifyCollection(viewModel.Children, viewModel, 0, 2, 0);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            viewModel.Children.Clear(false);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            viewModel.Children.Clear(true);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 6);
            Assert.AreEqual(childPropertyChanges[0], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[1], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[2], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[3], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[4], "ContainsRemovedModels");
            Assert.AreEqual(childPropertyChanges[5], "IsDirty");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Add(new ModelForCollectionTesting[] { child1, child2, child3 });

            VerifyCollection(viewModel.Children, viewModel, 3, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 11);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[4], "IsDirty");
            Assert.AreEqual(childPropertyChanges[5], "Count");
            Assert.AreEqual(childPropertyChanges[6], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[7], "AddedModels");
            Assert.AreEqual(childPropertyChanges[8], "Count");
            Assert.AreEqual(childPropertyChanges[9], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[10], "AddedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Reset();
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Add(new ModelForCollectionTesting[] { child1, child2, child3 }, true);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 3);
            Assert.AreEqual(childPropertyChanges.Count, 10);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[3], "ContainsCommittedModels");
            Assert.AreEqual(childPropertyChanges[4], "Count");
            Assert.AreEqual(childPropertyChanges[5], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[6], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[7], "Count");
            Assert.AreEqual(childPropertyChanges[8], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[9], "CommittedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);

            viewModel.Children.Clear(true);
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();
            viewModel.Children.Add(new ModelForCollectionTesting[] { }, true);

            VerifyCollection(viewModel.Children, viewModel, 0, 0, 0);
            Assert.AreEqual(childPropertyChanges.Count, 0);
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 0);

            viewModel.Children.Clear(true);
            viewModel.Children.Add(new ModelForCollectionTesting[] { child1, child2, child3 });
            viewModel.Children.Add(new ModelForCollectionTesting[] { child4, child5, child6 }, true);
            viewModel.Children.Remove(child5);
            addedChildrenIndexes.Clear();
            removedChildrenIndexes.Clear();
            childPropertyChanges.Clear();
            childPropertyCollectionChanges.Clear();

            viewModel.Children.AssignDefaultValue();

            VerifyCollection(viewModel.Children, viewModel, 0, 3, 0);
            Assert.AreEqual(childPropertyChanges.Count, 21);
            Assert.AreEqual(childPropertyChanges[0], "Count");
            Assert.AreEqual(childPropertyChanges[1], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[2], "AddedModels");
            Assert.AreEqual(childPropertyChanges[3], "Count");
            Assert.AreEqual(childPropertyChanges[4], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[5], "AddedModels");
            Assert.AreEqual(childPropertyChanges[6], "Count");
            Assert.AreEqual(childPropertyChanges[7], "AddedModelCount");
            Assert.AreEqual(childPropertyChanges[8], "AddedModels");
            Assert.AreEqual(childPropertyChanges[9], "ContainsAddedModels");
            Assert.AreEqual(childPropertyChanges[10], "Count");
            Assert.AreEqual(childPropertyChanges[11], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[12], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[13], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[14], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[15], "Count");
            Assert.AreEqual(childPropertyChanges[16], "RemovedModelCount");
            Assert.AreEqual(childPropertyChanges[17], "RemovedModels");
            Assert.AreEqual(childPropertyChanges[18], "CommittedModelCount");
            Assert.AreEqual(childPropertyChanges[19], "CommittedModels");
            Assert.AreEqual(childPropertyChanges[20], "ContainsCommittedModels");
            Assert.AreEqual(addedChildrenIndexes.Count, 0);
            Assert.AreEqual(removedChildrenIndexes.Count, 0);
            Assert.AreEqual(childPropertyCollectionChanges.Count, 1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item1);
            Assert.IsNull(childPropertyCollectionChanges[0].Item2);
            Assert.AreEqual(childPropertyCollectionChanges[0].Item3, NotifyCollectionChangedAction.Reset);
        }

        private static void AssertDefaultState<T>
        (
            ModelCollection<T> property,
            ModelBase parent,
            String name
        ) where T : ModelBase, new()
        {
            Assert.AreEqual(property.AddedModelCount, 0);
            Assert.AreEqual(property.RemovedModelCount, 0);
            Assert.AreEqual(property.CommittedModelCount, 0);

            Assert.AreEqual(property.GetAddedModels().Count(), 0);
            Assert.AreEqual(property.GetRemovedModels().Count(), 0);
            Assert.AreEqual(property.GetCommittedModels().Count(), 0);

            Assert.AreEqual(property.AddedModels.Count(), 0);
            Assert.AreEqual(property.RemovedModels.Count(), 0);
            Assert.AreEqual(property.CommittedModels.Count(), 0);

            Assert.IsFalse(property.ContainsAddedModels);
            Assert.IsFalse(property.ContainsRemovedModels);
            Assert.IsFalse(property.ContainsCommittedModels);

            Assert.AreEqual(property.Count, 0);
            Assert.AreEqual(property.Parent, parent);
            Assert.AreEqual(property.Name, name);
            Assert.AreEqual(property.IsWrapped, false);
            Assert.AreEqual(property.Behavior, ModelBase.StandardBehaviors);
            Assert.AreEqual(property.IsDirty, false);
            Assert.IsFalse(property.IsReadOnly);
            Assert.AreEqual(property.PropertyType, typeof(T));
            Assert.IsFalse(property.IsModelProperty);
            Assert.IsTrue(property.IsModelCollectionProperty);
        }

        private static void VerifyCollection<T>
        (
            ModelCollection<T> property,
            ModelBase parent,
            Int32 added,
            Int32 removed,
            Int32 committed
        ) where T : ModelBase, new()
        {
            Assert.AreEqual(property.IsDirty, (added + removed) > 0 && property.CheckSetsIsDirty());
            Assert.AreEqual(property.Count, added + committed);
            Assert.AreEqual(property.AddedModelCount, added);
            Assert.AreEqual(property.RemovedModelCount, removed);
            Assert.AreEqual(property.CommittedModelCount, committed);

            Assert.AreEqual(property.GetAddedModels().Count(), added);
            Assert.AreEqual(property.GetRemovedModels().Count(), removed);
            Assert.AreEqual(property.GetCommittedModels().Count(), committed);

            Assert.AreEqual(property.AddedModels.Count(), added);
            Assert.AreEqual(property.RemovedModels.Count(), removed);
            Assert.AreEqual(property.CommittedModels.Count(), committed);

            Assert.AreEqual(property.ContainsAddedModels, added > 0);
            Assert.AreEqual(property.ContainsRemovedModels, removed > 0);
            Assert.AreEqual(property.ContainsCommittedModels, committed > 0);

            for (Int32 index = 0; index < property.Count; index++)
            {
                var childModel = property[index];
                Assert.AreEqual(property.IndexOf(childModel as T), index);
            }

            for (Int32 index = 0; index < property.AddedModelCount; index++)
            {
                var childModel = property.GetAddedModels().ElementAt(index);
                Assert.AreEqual(childModel, property.AddedModels.ElementAt(index));
                VerifyChildAddedToCollection<T>(property, childModel as T);
            }

            for (Int32 index = 0; index < property.RemovedModelCount; index++)
            {
                var childModel = property.GetRemovedModels().ElementAt(index);
                Assert.AreEqual(childModel, property.RemovedModels.ElementAt(index));
                VerifyChildRemovedFromCollection<T>(property, childModel as T);
            }

            for (Int32 index = 0; index < property.CommittedModelCount; index++)
            {
                var childModel = property.GetCommittedModels().ElementAt(index);
                Assert.AreEqual(childModel, property.CommittedModels.ElementAt(index));
                VerifyChildCommittedToCollection<T>(property, childModel as T);
            }
        }

        private static void VerifyChildAddedToCollection<T>(ModelCollection<T> property, T viewModel)
            where T : ModelBase, new()
        {
            Assert.AreEqual(viewModel.ParentProperty, property);
            Assert.AreEqual(viewModel.Parent, property.Parent);
            Assert.IsTrue(viewModel.IsAddedToCollection);
            Assert.IsFalse(viewModel.IsRemovedFromParent);
            Assert.IsFalse(viewModel.IsRemovedFromCollection);
            Assert.IsFalse(viewModel.IsCommittedToCollection);
            Assert.IsTrue(property.Contains(viewModel));
            Assert.IsTrue(property.AddedModels.Contains(viewModel));
            Assert.IsFalse(property.CommittedModels.Contains(viewModel));
            Assert.IsFalse(property.RemovedModels.Contains(viewModel));
        }

        private static void VerifyChildCommittedToCollection<T>(ModelCollection<T> property, T viewModel)
            where T : ModelBase, new()
        {
            Assert.AreEqual(viewModel.ParentProperty, property);
            Assert.AreEqual(viewModel.Parent, property.Parent);
            Assert.IsFalse(viewModel.IsAddedToCollection);
            Assert.IsFalse(viewModel.IsRemovedFromParent);
            Assert.IsFalse(viewModel.IsRemovedFromCollection);
            Assert.IsTrue(viewModel.IsCommittedToCollection);
            Assert.IsTrue(property.Contains(viewModel));
            Assert.IsFalse(property.AddedModels.Contains(viewModel));
            Assert.IsTrue(property.CommittedModels.Contains(viewModel));
            Assert.IsFalse(property.RemovedModels.Contains(viewModel));
        }

        private static void VerifyChildRemovedFromCollection<T>(ModelCollection<T> property, T viewModel)
            where T : ModelBase, new()
        {
            Assert.AreEqual(viewModel.ParentProperty, property);
            Assert.AreEqual(viewModel.Parent, property.Parent);
            Assert.IsFalse(viewModel.IsAddedToCollection);
            Assert.IsTrue(viewModel.IsRemovedFromParent);
            Assert.IsTrue(viewModel.IsRemovedFromCollection);
            Assert.IsFalse(viewModel.IsCommittedToCollection);
            Assert.IsFalse(property.Contains(viewModel));
            Assert.IsFalse(property.AddedModels.Contains(viewModel));
            Assert.IsFalse(property.CommittedModels.Contains(viewModel));
            Assert.IsTrue(property.RemovedModels.Contains(viewModel));
        }

        private static void VerifyChildPurgedFromCollection<T>(ModelCollection<T> property, T viewModel)
            where T : ModelBase, new()
        {
            Assert.IsNull(viewModel.ParentProperty);
            Assert.IsNull(viewModel.Parent);
            Assert.IsFalse(viewModel.IsAddedToCollection);
            Assert.IsFalse(viewModel.IsRemovedFromParent);
            Assert.IsFalse(viewModel.IsRemovedFromCollection);
            Assert.IsFalse(viewModel.IsCommittedToCollection);
            Assert.IsFalse(property.Contains(viewModel));
            Assert.IsFalse(property.AddedModels.Contains(viewModel));
            Assert.IsFalse(property.CommittedModels.Contains(viewModel));
            Assert.IsFalse(property.RemovedModels.Contains(viewModel));
        }
    }
}
